/**	@file Sa2dDom.h
	@brief Defintions of all the classes used to build the Domain Object Module (DOM).

		The elements of the XML file are represented by the classes defined herein.
		Adding a new element on the XML file implies that a class has to be added here.
		
		Each Class is inherits from the domainObject class.
		
		All fields must be private. Consequently getter and setter functions must
		be defined.
		
		The implentation of the each Class must be provided in a separated .cpp file.
		<Class name>.cpp
		
	@author Andri Lareida.
	@author Documentation by: J.P. Carbajal
		
	@date 20. August, 2009
	
*/	
#ifndef SA2DDOM_H_
#define SA2DDOM_H_

#define RAD2ANG 57.295779513082322864647721871734
#define ANG2RAD 0.017453292519943295474371680597869

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <map>
#include <sstream>



using namespace std;

/**	@class domainObject
	@brief Parent object for all the DOM classes.
	
	The class contains some methods to read from the input file.
*/
class domainObject {

public:
	virtual string toString(int indent){
		return "";
	};

	string toString(){
		return this->toString(0);
	}
	string getIndent(int indent){

		stringstream str;
		for(int i = 0;i<indent;i++){
			str<<"\t";
		}
		return str.str();
	}

};

/**	@class angle
	@brief A class to read angle values.
	
	The class is used to store angle values. The class assumes that the data is 
	given in radians.
*/
class angle : public domainObject {
private:
	float angleDegree;

public:
	angle();
	float getDegree();
	float getRadian();
	void setDegree(float degrees);
	void setRadian(float radians);

	virtual string toString(int indent);
};

/**	@class rotation
	@brief This class stores the information of a general rotation in 3D. This 
	is used in the definition of the border of the Arena, NOT IMPLEMENTED.
	
	The class stores the rotation angles around the three acxis, that defines 
	the oritentation of a body in 3D. It is not used in the program. NOT USED.
*/
class rotation  : public domainObject {

private:
	double angle_x;
	double angle_y;

public:
	rotation();
	rotation(double x, double y);

    double getAngle_x();

    double getAngle_y();

    void setAngle_x(double angle_x);

    void setAngle_y(double angle_y);

    virtual string toString(int indent);

};

/**	@class vertex
	@brief A class stroring the information of a vertex. It is a named point in 
	2D.
*/
class vertex : domainObject{

private:
	string name;
	double x;
	double y;

public:
	vertex();

    string getName();

    double getX();

    double getY();

    void setName(string name);

    void setX(double x);

    void setY(double y);

    virtual string toString(int indent);

};

/**	@class windowSettings
	@brief Class storing the Height and Width of a window used to visualize the 
	simulation.
*/
class windowSettings  : public domainObject {

private:
	string name;
	int width;
	int height;

public:
	windowSettings();

	const int getHeight();

	const string getName();

	const int getWidth();

	void setHeight(int height);

	void setName(string name);

	void setWidth(int width);

	virtual string toString(int indent);

};

/**	@class physicsEngine
	@brief This class stores the information of the Physics Engine.
	
	This class stores parameters for the physics engine. 
	There are general parameters that has to be set for any engine, gravity and 
	damping.
	The other parameters are related to the Space Hash collision detection 
	algortihm used in Chipmunk. 
	
	@todo The collision detection should be a sub-element of the Physics Engine.
*/
class physicsEngine  : public domainObject {

private:
	string name;
	double gravity;
	double damping;
	int static_shape_hash_dim;
	int active_shape_hash_dim;
	int static_shape_hash_count;
	int active_shape_hash_count;

public:

	const int getActive_shape_hash_count();

	const int getActive_shape_hash_dim();

	const double getDamping();

	const double getGravity();

	const string getName();

	const int getStatic_shape_hash_count();

	const int getStatic_shape_hash_dim();

	void setActive_shape_hash_count(int active_shape_hash_count);

	void setActive_shape_hash_dim(int active_shape_hash_dim);

	void setDamping(double damping);

	void setGravity(double gravity);

	void setName(string name);

	void setStatic_shape_hash_count(int static_shape_hash_count);

	void setStatic_shape_hash_dim(int static_shape_hash_dim);

	virtual string toString(int indent);

};

/** @class position
	@brief Class storing a point in 2D space.
*/
class position  : public domainObject {

private:
	double x;
	double y;

public:
	position();

	position(double x, double y);

    double getX();

    double getY();

    void setX(double x);

    void setY(double y);

    virtual string toString(int indent);

};

/** @class render
	@brief Class storing parameters related with the render.
	
	The class stores parameters related to the rendering process, like fps
	the number of windows to show the output and the scale.
	The scale defines the relation between screen units (pixels) and the 
	simulation units (meters, cm, mm, etc...). It should be given in 
	pixels/simulation-unit.
	
	@todo fps, scale and multiple windows are not implemented.
*/
class render : public domainObject {

private:
	string name;
	float scale;
	double fps;
	int win_qty;
	vector<windowSettings*> mywindows;

public:
	render();

	const double getFps();

	std::vector<windowSettings*>::iterator getMywindows();

	windowSettings* getFirstWindow();

	const string getName();

	const float getScale();

	const int getWin_qty();

	void setFps(double fps);

	void setName(string name);

	void setScale(float scale);

	void setWin_qty(int win_qty);

	void addWindow(windowSettings *window);

	virtual string toString(int indent);


};

/** @class paramSet
	@brief A class to store an arbitrary set of parameters.
	
	A parameterSet has a name and a number of values. One of the parameters
    (source) could be a pointer to another class, file or function, it is a 
	string.
*/
class paramSet  : public domainObject {

private:
	string name;
	string source;
	int param_qty;
	map<string, string> params;

public:
	paramSet();

    string getParam(string key);

    string getName();

    int getParam_qty();

    string getSource();

    void addParam(string key, string param);

    void setName(string name);

    void setParam_qty(int param_qty);

    void setSource(string source);

    map<string, string> getParams();

    virtual string toString(int indent);

};

/** @class geometry
	@brief Class containing the description of a polygon object
	
	This class contains the fields defining a 2D polygon. It is inspired on the
	struture provided by Chipmunk. A polygon has a type and a set of vertices 
	defining it.
*/
class geometry: public domainObject {

private:
	string shape_type;
	std::vector<vertex*> vertices;

public:
	geometry();

    string getShape_type();

    std::vector<vertex*> getVertices();

    void setShape_type(string shape_type);

    void setVertices(std::vector<vertex*> vertices);

    void addVertice(vertex * vertex);

    virtual string toString(int indent);

};

/** @class circularGeometry
	@brief Class containing the description of a circle
	
	This class contains the fields defining a circle. It is inspired on the
	struture provided by Chipmunk. 
*/
class circularGeometry: public geometry {

public:
	float radius;
public:
	circularGeometry();
	float getRadius();
	void setRadius(float radius);
	virtual string toString(int indent);
};

/** @class physicalProperties
	@brief Class containing the description of body with physics.
	
	This class contains the fields defining parameters related to the  physical
	behavior of a body. It is based on struture provided by Chipmunk. 
*/
class physicalProperties : public domainObject {

private:
	double elasticity;
	double friction;
	double mass;
	double surface_speed;
	position *mycenterOfMass;

public:
	physicalProperties();

    double getElasticity();

    double getFriction();

    double getMass();

    position *getCenterOfMass();

    void setElasticity(double elasticity);

    void setFriction(double friction);

    void setMass(double mass);

    void setCenterOfMass(position *mycenterOfMass);

    double getSurface_speed();

    void setSurface_speed(double surface_speed);

    virtual string toString(int indent);

};

/** @class shape
	@brief Class containing the shape description used t read the Arena border
	@todo This class cmust be merged to general one. The idea is that any shape 
	in the description of thesimulation should be loaded using the same type of 
	object. Also, even without a general object this class could be reorganized 
	to contai physical Properties instead of a redefinition of the fields.
*/
class shape: public domainObject {

private:
	string name;
	double elasticity;
	double friction;
	double surface_speed;
	position *myposition;
	rotation *myrotation;
	geometry *mygeometry;

public:
	shape();

    double getElasticity();

    double getFriction();

    geometry *getGeometry();

    position *getPosition();

    rotation *getRotation();

    string getName();

    double getSurface_speed();

    void setElasticity(double elasticity);

    void setFriction(double friction);

    void setGeometry(geometry *mygeometry);

    void setPosition(position *myposition);

    void setRotation(rotation *myrotation);

    void setName(string name);

    void setSurface_speed(double surface_speed);

    virtual string toString(int indent);

};

/** @class singularity
	@brief Class containing the description of a singularity
	
	A singularity described point entities that are the sources of physical 
	interaction between two any bodies in the simulation. Singulrities could be
	electric charges, point dipoles (magents), and these ones could be 
	perpendicular to the plane of the simulation or on it.
	
	@todo The magnets could be generelized to a point dipole with arbotrary 3D 
	orientation by using the vectorized formula of interaction between magnetics
	dipoles.
*/
class singularity: public domainObject {

private:
	string name;
	string type;
	double value;
	position *myposition;
	angle* myangle;

public:
	singularity();

    position *getPosition();

    string getName();

    string getType();

    double getValue();

    angle* getAngle();

    void setPosition(position *myposition);

    void setName(string name);

    void setType(string type);

    void setValue(double value);

    void setAngle(angle * anangle);

    virtual string toString(int indent);

};

/** @class agentSet
	@brief Class containing the description of a set of agents
	
	When describing the agents in the simulation it is useful to be able to 
	describe all  the ones that share the same properties as one set. If there 
	are no agents that are equal in ist properties each set has only one element.
	If there are agents that share properties the set will contain that many 
	elements.
	An agent is described by its geometry, the singularities it contains, its
	physical properties and the controller it has (the artificial intelligence).
	
	@todo AI is not implemented
*/
class agentSet : public domainObject {

private:

	string name;
	int elem_quantity;
	paramSet* initialCondition;
	std::vector<singularity*> singularities;
	std::vector<paramSet*> artificialIntelligence;
	geometry *mygeometry;
	physicalProperties *myphysicalProperties;

public:
	agentSet();

	string getName();

	std::vector<paramSet*> getArtificialIntelligence();

	int getElem_quantity();

	paramSet* getInitialCondition();

	geometry *getGeometry();

	physicalProperties *getPhysicalProperties();

	std::vector<singularity*> getSingularities();

	void setArtificialIntelligence(std::vector<paramSet*> artificialIntelligence);

	void setElem_quantity(int elem_quantity);

	void setInitialCondition(paramSet * initialCondition);

	void setGeometry(geometry *mygeometry);

	void setPhysicalProperties(physicalProperties *myphysicalProperties);

	void setName(string name);

	void setSingularities(std::vector<singularity*> singularities);

	virtual string toString(int indent);

	void addSingularity(singularity * singularity);

	void addArtificialIntelligence(paramSet * ai);

};

/** @class arenaBorder
	@brief Class containing the description of the boundary of the arena
	
	The simulations could be bounded by a fisical limit (the border or boundary)
	of the arena, like "walls". The border could also be obstacles (the arena 
	does not need to be a connected set). Here we store the information to 
	describe such arena.
*/
class arenaBorder: public domainObject {

private:

	//TODO, andri: rename to componentType
	string uses;
	int quantity;
	string distribution;
	std::vector<shape*> myshape;
	double radius;

public:
	arenaBorder();

    string getDistribution();

    int getQuantity();

    string getUses();

    void setDistribution(string distribution);

    void setMyshape(std::vector<shape*> myshape);

    void setQuantity(int quantity);

    void setUses(string uses);

    virtual string toString(int indent);

    std::vector<shape*> getShapes();

    void addShape(shape *shape);

    void setRadius(double rad);

    double getRadius();

};

/** @class arena
	@brief Class containing the description of the arena. It shoould be just a 
	composition of Border and physical properties...
	
	@see arenaBorder
*/
class arena: public domainObject {

private:
	int radius;
	int elasticity;
	double friction;
	double surface_speed;
	arenaBorder *myborder;

public:
	arena();

    int getElasticity();

    double getFriction();

    arenaBorder *getBorder();

    int getRadius();

    double getSurface_speed();

    void setElasticity(int elasticity);

    void setFriction(double friction);

    void setMyborder(arenaBorder *myborder);

    void setRadius(int radius);

    void setSurface_speed(double surface_speed);

    virtual string toString(int indent);

};

/** @class performer
	@brief Class containing the description of sotfware that will run the 
	simulation describe din the input file.
	
	This class contains parameters that a program running the simulation 
	described in the input file should need. At the moment there is only one
	performer.
*/
class performer: public domainObject {

private:
	string name; //! < name of the performer
	int dim; //! < dimensions of the simulation
	int iterations; //! < number of iterations to be claculated
	double total_time; //! < Total simulation time to be claculated
	int max_substeps; //! < number of substeps (subdivision of timestpes)
	render* myrender;

public:
	performer();

	render* getRender();

	const int getDim();

	const int getIterations();

	const int getMax_substeps();

	const string getName();

	const double getTotal_time();

	void setDim(int dim);

	void setIterations(int iterations);

	void setMax_substeps(int max_substeps);

	void setName(string name);

	void setTotal_time(double total_time);

	virtual string toString(int indent);

	virtual ~performer();

};

/** @class simulation
	@brief Class contianing the description of a simulation. 
	
	This class is high-level class composed of a Performer and a Physics engine.
*/
class simulation: public domainObject {

private:
	performer * myperformer;
	physicsEngine * myphysicsengine;

public:
	simulation();
	performer* getPerformer();
	physicsEngine* getPhysicsEngine();
	virtual string toString(int indent);
	virtual ~simulation();

};

/** @class configurationfile
	@brief Class contianing the description of a simulation inpuit file. 
	
	This class reproduces the structure of the input file. Information about
	the simulation in general, the arena, and the agets is stored.
*/
class configurationfile: public domainObject {

private:
	string file_name;

	string file_date;

	simulation * mySimulation;

	arena *myArena;

	vector<agentSet*> agentSetVector;

	void constructor();

public:

	configurationfile();
	configurationfile(string fileDate);

	string getFileName();

	void setFileName(string name);

	string getFileDate();

	vector<agentSet*> getAgentSets();

	arena *getArena();

	simulation *getSimulation();

	void setFileDate(string file_date);

	void addAgent(agentSet* anAgent);

	virtual string toString(int indent);

	virtual ~configurationfile();
};

#endif /* SA2DDOM_H_ */
